package edu.siu.math.egut.util;
 

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
 

/**
 * 
 * A data structure which represents, for our purposes, a split, connected,
 * simply connected simple algebraic group.
 * Essentially a bundle of important structural invariants of such an object as
 * follows: 
 * (1) a list of positive roots (defining an order on this set) 
 * (2) a list of negative roots 
 * (3) a "Cayley table" for addition of roots.
 * (4) a matrix containing the structure constants N(a,b) for a,b,
 * positive roots. 
 * (5) a "Cayley table" for commutator of simple unipotents
 * (6) the lengths of the roots (normalized so that short roots are length 1) 
 * (7) the Cartan matrix
 * (8) the matrix representing the Weyl group invariant inner
 * product with respect to the basis of simple roots, normalized so that the
 * entries are integers with gcd 1.
 * 
 * 
 * @author Joe Pleso
 * 
 */
public class ExceptionalGroup implements Serializable {


    /**
     * 
     */
    private static final long serialVersionUID = 226L;
    
    private static final String[] FILENAMES = 
    	{null,
	 null,"G2.ser",null,"F4.ser",
	 null,"E6.ser","E7.ser","E8.ser"};
    


    /**
     * Reflects a toral element over a specified simple reflection.
     * 
     * @param simpleIndex the index of the simple reflection 
     * @param l the toral element
     * @return the new toral element
     */
    public List<LaurentPolynomial> getSimpleReflectionToral(
	    int simpleIndex, 
	    List<LaurentPolynomial> l) {
	List<LaurentPolynomial> result = new ArrayList<LaurentPolynomial>();
	if (getRank() == 2) {
	    if (simpleIndex == 0){
		result.add(l.get(1));
		result.add(l.get(0));
		return result;
	    }
	    result.add(l.get(0).times(l.get(1)));
	    result.add(l.get(1).inverse());
	    return result;
	}
	throw new RuntimeException("only G2 supported.");
	
    }
    
    /**
     * Returns the Weyl root data.
     * 
     * @return the Weyl root data
     */
    public int[][] getWeylRoots (){
	return ExceptionalGroupData.getWeylRoots(getRank());
    }
    
    /**
     * Return the Weyl sign data.
     * 
     * @return the Weyl sign data
     */
    public int[][] getWeylSigns(){
	return ExceptionalGroupData.getWeylSigns(getRank());
    }
    
    
    

    private static void saveGroup (String filename, ExceptionalGroup g){

	try{
	    //use buffering
	    OutputStream file = new FileOutputStream( filename);
	    OutputStream buffer = new BufferedOutputStream( file );
	    ObjectOutput output = new ObjectOutputStream( buffer );
	    try{
		output.writeObject(g);
	    }
	    finally{
		output.close();
	    }
	}  
	catch(IOException ex){
	    System.err.println(ex);
	}

    }

    /**
     * Returns the weight of a root -- that is, the sum of the entries.
     * 
     * @param root the root to check
     * @return the weight of the root
     */
    public static int getWeight (int[] root){
	int sum = 0;
	for (int i = 0; i < root.length; i++)
	    sum += root[i];
	return sum;
    }

   
    private static ExceptionalGroup loadGroup (String filename){


	try{
	    //use buffering
	    InputStream file = new FileInputStream( filename );
	    InputStream buffer = new BufferedInputStream( file );
	    ObjectInput input = new ObjectInputStream ( buffer );
	    try{
		//deserialize the List
		return (ExceptionalGroup)input.readObject();

	    }
	    finally{
		input.close();
	    }
	}
	catch(ClassNotFoundException ex){
	    System.err.println(ex);
	}
	catch(IOException ex){
	    System.err.println(ex);
	}



	return null;


    }

    
    /**
     * Creates a toral element in this group.
     * 
     * @param t the list of rank polynomials
     * @return a toral element
     */
    public ExceptionalGroupElement h (List<LaurentPolynomial> t){
	
	List<SimpleUnipotentElement> l = new ArrayList<SimpleUnipotentElement>();
	
	
	
	return new ExceptionalGroupElement(this, l, t);
    }
    /**
     * Creates a toral element in this group.
     * @param root the root
     * 
     * @param t the polynomials
     * @return a toral element
     * @throws NotARootException thrown if root is not a root
     */
    public ExceptionalGroupElement h (int[] root, LaurentPolynomial t)
    throws NotARootException{
	if (isNegative(root))
	    return h(negative(root), t.inverse());
	if (this.getRank() == 2){
	List<SimpleUnipotentElement> l = new ArrayList<SimpleUnipotentElement>();
	List<LaurentPolynomial> result =
	    new ArrayList<LaurentPolynomial>();
	int index = findIndex(root);
	switch (index){
	//{ 0, 1 }, { 1, 0 }, { 1, 1 },{ 1, 2 }, { 1, 3 }, { 2, 3 } };
	case 0: 
	    result.add(t.inverse());
	    result.add(t.times(t));
	    break;
	case 1:
	    result.add(t);
	    result.add(t.inverse());
	    break;
	case 2:
	    result.add(t.times(t));
	    result.add(t.inverse());
	    break;
	case 3:
	    result.add(t);
	    result.add(t);
	    break;
	case 4:
	    result.add(LaurentPolynomial.create(1));
	    result.add(t);
	    break;
	case 5:
	    result.add(t);
	    result.add(LaurentPolynomial.create(1));
	    break;
	}
	
	return new ExceptionalGroupElement(this, l, result);
	}
	throw new RuntimeException("Only G2 supported.");
    }

    LaurentPolynomial rootActingOnTorus (int[] root,
	    List<LaurentPolynomial> t){
	if(this.getRank()==2){
	    LaurentPolynomial result = LaurentPolynomial.create(1);
	
	
	result = result.times(t.get(0).raiseTo(root[0]));
	result = result.times(t.get(1).raiseTo(root[1]-root[0]));
	
	return result;
	}
	throw new RuntimeException("Only G2 supported.");
    }

    private static final String rString = 
	"_RESERVED_r";

    private static final String sString = 
	"_RESERVED_s";
    /**
     * Used for replacements of toral elements.
     */
    public static final String tString = "_RESERVED_t";
    

    /**
     * The way to get a copy of your favorite exceptional group.
     * 
     * @param rank the rank of your favorite exceptional group
     * @return your favorite exceptional group
     */
    public static ExceptionalGroup getGroup(int rank) {/*@\label{eggetGroup}@*/
	ExceptionalGroup g = cachedGroups[rank];
	if (g != null) //if cached, return that copy.
	    return g;
	//otherwise try to deserialize from file
	g = loadGroup(FILENAMES[rank]);  
	cachedGroups[rank] = g;
	if (g != null) //check to see if deserialization was successful
	    return g; 
        //otherwise we must actually build the group from scratch
	System.out.println(
	    "Generating exceptional group of rank " + rank + "...");
	g = new ExceptionalGroup(rank);
	//we now cache and serialize before returning
	cachedGroups[rank] = g; 
	saveGroup(FILENAMES[rank], g); 
	return g;    
	
    }/*@\label{eggetGroupend}@*/






    private final static  ExceptionalGroup[] cachedGroups 
        = new ExceptionalGroup[9];
    /**
     * Returns the commutator [s1,s2]=s1 s2 s1^{-1} s2^{-1} of two Sunipotents, 
     *  as a list of sunipotents.
     *  (In practice this is more useful than returning a Unipotent.) 
     *  
     * 
     * @param s1            the first sunipotent
     * @param s2            the second sunipotent
     * 
     * @return the commutator [a,b]
     * 
     * 
     */

    

    public List<SimpleUnipotentElement> commutator(
	    SimpleUnipotentElement s1,
	    SimpleUnipotentElement s2) {
	int signOffset = 0;
	int aPos;
	int bPos;
	if (!isPositive(s1.getRoot())) {
	    signOffset += 1;
	    try {
		aPos = findIndex(negative(s1.getRoot()));
	    } catch (NotARootException e) {
		throw new RuntimeException();
	    }
	} else {
	    aPos = findIndex(s1.getRoot());
	}
	if (!isPositive(s2.getRoot())) {
	    signOffset += 2;
	    try {
		bPos = findIndex(negative(s2.getRoot()));
	    } catch (NotARootException e) {
		throw new RuntimeException();
	    }
	} else {
	    bPos = findIndex(s2.getRoot());
	}

	
	List<SimpleUnipotentElement> replacement = replacements.get(
		positiveRoots.length
		* positiveRoots.length * signOffset 
		+ positiveRoots.length * aPos + bPos);

	

	List<SimpleUnipotentElement> result = 
	    new ArrayList<SimpleUnipotentElement>();
	if( replacement != null){
	    for (SimpleUnipotentElement s : replacement) {
		LaurentPolynomial p = s.getPolynomial();
		p=p.replace( rString,s1.getPolynomial());
		p=p.replace( sString,s2.getPolynomial());




		result.add(SimpleUnipotentElement.create(s.getRoot(), p));
	    }
	}
	return result;
    }

    private int normSquared(int[] root) {
	return normSquares[findIndex(root)];
    }

    /**
     * Used to determine if a root is negative.
     * 
     * @param a the root to check
     * @return true if root is negative, false otherwise
     */
    public static boolean isNegative( int[]a){


	for( int i = 0 ; i < a.length; i++ )
	    if( a[i] <0 )
		return true;

	return false;
    }

    private ArrayList<SimpleUnipotentElement> internalCommutator(
	    SimpleUnipotentElement s1, SimpleUnipotentElement s2) {

	ArrayList<SimpleUnipotentElement> result = 
	    new ArrayList<SimpleUnipotentElement>();

	LaurentPolynomial p1 = s1.getPolynomial();
	LaurentPolynomial p2 = s2.getPolynomial();
	int[] a =s1.getRoot();
	int[] b = s2.getRoot();

	int[] ab;
	ab = sums.add(a,b);
	if( isRoot(ab)){
	    LaurentPolynomial pab =
		p1.times((LaurentPolynomial) p2);
	    int cab =getStructureConstant(a,b);


	    result.add(SimpleUnipotentElement.create(ab, pab.times(
		    LaurentPolynomial.create(cab ))));


	   /**/

	    int[] aab;
	    aab = sums.add(a, ab);
	    if( isRoot( aab) ){
		LaurentPolynomial paab = pab.times(p1);
		int caab = cab*getStructureConstant(a, ab) /2;
		result.add(SimpleUnipotentElement.create(aab, paab.times(
			LaurentPolynomial.create(caab))));

		/**/

		int[] aaab = sums.add(a, aab);
		if(isRoot(aaab)){
		   
		    LaurentPolynomial paaab = paab.times(p1);
		    int caaab =caab*getStructureConstant(a,aab)/3;

		    result.add(SimpleUnipotentElement.create(aaab, paaab.times(
			    LaurentPolynomial.create(caaab))));

		    /**/

		    int[] aaabb = sums.add(b, aaab);
		    if( isRoot(aaabb))
		    {

			
			LaurentPolynomial paaabb = paaab.times(p2);
			int caaabb = 2*caaab*getStructureConstant(b, aaab);

			result.add(SimpleUnipotentElement.create( aaabb,
				paaabb.times(LaurentPolynomial.create(
					caaabb))));
		    }
		}
	    }

	    int[] abb;
	    abb = sums.add(ab, b);
	    if( isRoot(abb))
	    {
		LaurentPolynomial pabb = pab.times(p2);
		int cabb = cab*getStructureConstant(b, ab) /2;
		result.add(SimpleUnipotentElement.create(abb, pabb.times(
			LaurentPolynomial.create(cabb))));

		/**/

		int[] abbb = sums.add(b, abb);
		if(isRoot(abbb)){
		   
		    LaurentPolynomial pabbb = pabb.times(p2);
		    int cabbb =cabb*getStructureConstant(b,abb)/3;

		    result.add(SimpleUnipotentElement.create(abbb, pabbb.times(
			    LaurentPolynomial.create(cabbb))));

		   /**/

		    int[] aabbb = sums.add(a, abbb);
		    if( isRoot(aabbb))
		    {

	
			LaurentPolynomial paabbb = pabbb.times(p1);
			int caabbb = -1*cabbb*getStructureConstant(a, abbb);

			result.add(SimpleUnipotentElement.create( aabbb, 
				paabbb.times(
				LaurentPolynomial.create(caabbb))));
		    }
		}
	    }
	}
	return result;
    }

    /**
     * Finds the index of root in the int[][] roots
     * 
     * @param roots
     *            a int[][] to search in
     * @param root
     *            a int[] to find in roots
     * @return the index such that roots[index]==root is true, or -1 if a match
     *         was not found
     */
    private int findIndex(int[][] roots, int[] root) {
	for (int i = 0; i < roots.length; i++)
	    if (Arrays.equals(root, roots[i]))
		return i;
	return -1;
    }

    
    /**
     * Finds the index of a root in the list of all roots.
     *  
     * @param root the root
     * @return the index
     */
    public int findIndex(int[] root) {
	return findIndex(roots, root);
    }
    
    /**
     * Computes the factor that should be applyed to the
     * polynomial of the one parameter subgroup
     * associated with the specified root when reflected over the specified
     * simple root.
     * 
     * @param simpleIndex the index of the simple root
     * @param root the root to be reflected
     * @return the sign
     */
    public LaurentPolynomial getSimpleReflectionSign(
	    int simpleIndex, int[] root){

	int[][] signData = this.getWeylSigns();
	
	
	    return LaurentPolynomial.create(
		    signData[findIndex(root)%6][simpleIndex]);
    }
    
    
    /**
     * Reflects the specified root by the specified simple reflection.
     * 
     * @param simpleIndex the index of the simple root to reflect over
     * @param root the root to be reflected
     * @return the root after the reflection
     * @throws NotARootException thrown if root is not a root
     */
    public int[] getSimpleReflectionRoot (int simpleIndex, int[] root)
    throws NotARootException{
	int[][] rootData = this.getWeylRoots();
	
	if (isNegative(root)){
	    int[] negRoot = negative(root);
	    return roots[rootData[findIndex(negRoot)][simpleIndex]+6%12];
	}else{
	    return roots[rootData[findIndex(root)][simpleIndex]];
	}
    }

    
    /**
     * Returns the coefficient from the structure constants matrix for given
     * roots a and b.
     * 
     * 
     * @param a            the first root
     * @param b            the second root
     * 
     * @return the coefficient from the structure constants matrix
     */
    public int getStructureConstant(int[] a, int[] b) {
	int[] c;
	c = sums.add(a, b);
	if (isRoot(c)) {
	    if (isPositive(a))
		if (isPositive(b))
		    return scm.get(a, b);
		else {
		    if (isPositive(c)) {
			try {
			    b = negative(b);
			} catch (NotARootException e) {
			    throw new RuntimeException();
			}
			if ((normSquared((c))) * scm.get(b, c) % normSquared(a)
				!= 0) {
			    throw new RuntimeException(
				    "sign algorithm is no good.  ");
			}
			return -1 * (normSquared((c))) * scm.get(b, c)
			/ normSquared(a);
		    } else
			try {
			    return this.getStructureConstant(negative(b),
				    negative(a));
			} catch (NotARootException e) {
			    throw new RuntimeException();
			}
		}
	    else 
	    {
		if (isPositive(b))
		    return -1 * this.getStructureConstant(b, a);
		else
		    try {
			return this.getStructureConstant(negative(b),
				negative(a));
		    } catch (NotARootException e) {
			throw new RuntimeException();
		    }
	    }
	} else
	    return 0;
    }

    private boolean isPositive(int[] root) {
	return findIndex(positiveRoots, (root)) >= 0;
    }

    /**
     * Checks to see if the argument that is passed to this method is , in fact,
     * a root in this root system.
     * 
     * @param root    check to see if this vector is a root in the root system
     * @return true if the vector was a root
     * 
     * 
     */

    public boolean isRoot(int[] root) {

	return findIndex(roots, root)>-1;
    }


    /**
     * Multiplies every vector in a list by -1.
     * 
     * @param v
     *            list of vectors
     * @return a new list with each element multiplied by -1.
     */
    private static int[][] negative(int[][] v) {
	int[][] result = new int[v.length][];
	for (int i = 0; i < result.length; i++) {
	    result[i] = new int[v[i].length];
	    for (int j = 0; j < v[i].length; j++) {
		result[i][j] = (-1 * v[i][j]);
	    }
	}
	return result;
    }

    /**
     * Negates a root.
     * 
     * @param root           a root in the group
     * @return the negative of the specified root
     * @throws NotARootException            thrown if the root is not a root
     */
    public int[] negative(int[] root) throws NotARootException {
	if (!isRoot(root))
	    throw new NotARootException();
	int i = findIndex(root);
	return this.roots[((i+positiveRoots.length)%(roots.length))];  
	
    }

    /**
     * Returns a very short string representing a root, which may be positive or
     * negative.
     * 
     * 
     * 
     * @param root          the root to convert to a string
     * @return a short string representation of the root
     */
    public String toString(int[] root) {

	StringBuffer sb = new StringBuffer();
	int sgn = 1;
	if (!isPositive(root))
	{
	    sb.append("-");
	    sgn = -1;
	}
	for (int i = 0; i < root.length; i++)
	    sb.append(sgn*root[i]);
	return sb.toString();

    }

    /**
     * Returns a string representation for the specified sunipotent in the
     * specified group.
     * 
     * @param s         the sunipotent to convert to a string
     * @return the string representation of s
     */
     String toString(SimpleUnipotentElement s) {
	ExceptionalGroup g = this;
	return "x_" + g.toString(s.getRoot()) + "(" + s.getPolynomial() + ")";
    }

    private final int[][] positiveRoots;

    private final int[][] negativeRoots; // = Algorithms.negative(roots);

    private final int[][] roots;

    private final VectorCayleyTable sums;// =

    // new VectorCayleyTable (roots);
    private final StructureConstantsMatrix scm;// =

    private final ArrayList<ArrayList<SimpleUnipotentElement>> replacements;

    private final int[] normSquares;

    private int[][] cartan;

    private final int[][] weylInvtInnProdMatrix;
    /**
     * Returns the matrix of the Weyl invariant inner product normalized so that 
     * short roots have length 2.
     * 
     * @return Weyl Invariant Inner Product Matrix, as int[][]
     */
    public int[][] getWeylInvtInnProdMatrix() {
	return weylInvtInnProdMatrix;
    }

   
    
    /**
     * Generates the image of a one parameter subgroup.
     * 
     * @param root the root
     * @param f the argument
     * @return the element of the group
     */
    public ExceptionalGroupElement chi(/*@\label{egchi}@*/
	    int[] root,
	    LaurentPolynomial f) {
	SimpleUnipotentElement psg = SimpleUnipotentElement.create(root, f);
	List<SimpleUnipotentElement> l = 
	    new ArrayList<SimpleUnipotentElement>();
	l.add(psg);
	List<LaurentPolynomial> g = 
	    new ArrayList<LaurentPolynomial>(this.getRank());
	LaurentPolynomial one = LaurentPolynomial.create(1);
	for (int i = 0; i < this.getRank(); i++)
	    g.add(one);
	
	return new ExceptionalGroupElement(this, l, g);
    }/*@\label{egchiend}@*/
    
       
    /**
     * Constructor for exceptional groups, which are, for our purposes, 
     * completely determined by their ranks.
     * For the most part, the relevant data is simply read in from the file 
     * EGData.java.
     * 
     * @param rank  The semisimple rank of the desired exceptional group Must 
     * equal 2,4,6,7, or 8.  For 
     * any other value a runtime error will be thrown.
     */
    private ExceptionalGroup(int rank) {

	
	this.positiveRoots = ExceptionalGroupData.positiveRoots(rank);
	this.negativeRoots = negative(positiveRoots);
	roots = new int[2*positiveRoots.length][rank];
	for( int i = 0 ; i < positiveRoots.length; i++)
	    for( int j = 0 ; j < rank ; j++)
		roots[i][j] = positiveRoots[i][j];
	for( int i = positiveRoots.length; i < roots.length; i++)
	    for( int j = 0 ; j < rank ; j++)
		roots[i][j] = negativeRoots[i-positiveRoots.length][j];

	this.sums = new VectorCayleyTable(roots);

	cartan = ExceptionalGroupData.cartan( rank);
	weylInvtInnProdMatrix = ExceptionalGroupData.weylInvtInnProd( rank );
	scm = ExceptionalGroupData.scm( rank);
	normSquares = ExceptionalGroupData.normSquares(rank);

	
	LaurentPolynomial rPoly;
	LaurentPolynomial sPoly;
	rPoly = LaurentPolynomial.create(rString);

	sPoly = LaurentPolynomial.create(sString);
	// Now we would like to create a bunch of commutators
	replacements = new ArrayList<ArrayList<SimpleUnipotentElement>>();

	for (int i = 0; i < positiveRoots.length; i++) {

	    for (int j = 0; j < positiveRoots.length; j++) {
		if (i != j){
		    replacements.add(this.internalCommutator(
			    SimpleUnipotentElement.create(
			    positiveRoots[i], rPoly), SimpleUnipotentElement
			    .create(positiveRoots[j], sPoly)));
		} else
		    replacements.add(null);
	    }
	}
	for (int i = 0; i < positiveRoots.length; i++) {

	    for (int j = 0; j < positiveRoots.length; j++) {
		if (i != j) {
		    replacements.add(this.internalCommutator(
			    SimpleUnipotentElement.create(
			    negativeRoots[i], rPoly),
			    SimpleUnipotentElement.create(
				    positiveRoots[j], sPoly)));
		} else
		    replacements.add(null);
	    }
	}
	for (int i = 0; i < positiveRoots.length; i++) {

	    for (int j = 0; j < positiveRoots.length; j++) {
		if (i != j) {
		    replacements.add(this.internalCommutator(
			    SimpleUnipotentElement.create(
			    positiveRoots[i], rPoly), 
			    SimpleUnipotentElement.create(
				    negativeRoots[j], sPoly)));
		} else
		    replacements.add(null);
	    }
	}
	for (int i = 0; i < positiveRoots.length; i++) {

	    for (int j = 0; j < positiveRoots.length; j++) {
		if (i != j) {
		    replacements.add(this.internalCommutator(
			    SimpleUnipotentElement.create(
			    negativeRoots[i], rPoly), 
			    SimpleUnipotentElement.create(
				    negativeRoots[j], sPoly)));
		} else
		    replacements.add(null);
	    }
	}

    }

    /**
     * Returns the list of negative roots.
     * 
     * @return the list of negative roots
     */
    public int[][] getNegativeRoots() {

	return (negativeRoots);
    }

    /**
     * Returns the list of positive roots.
     * 
     * @return the list of positive roots.
     */
    public int[][] getPositiveRoots() {

	return (positiveRoots);
    }



    /**
     * Gets list of all roots.
     * 
     * @return list of all roots
     */
    public int[][] getRoots() {/*@\label{eggetRoots}@*/
	return roots;
    }/*@\label{eggetRootsend}@*/
    
    /**
     * Gets the semisimple rank of this group.
     * 
     * @return the rank of the group
     * 
     * 
     */

    public int getRank() {

	return roots[0].length;
    }

    /**
     * Determines whether a collection u = { a1, a2, ... an} 
     * of roots of G defines a unipotent 
     * subgroup of the G, i.e., if the set of all elements of 
     * G of the form 
     * x_{a1}(r1) ... x_{an} (rn) 
     * is closed under multiplication.
     * 
     * An equivalent condition is that for a, b in u, either a+b is 
     * in u, or a+b is not a root.
     * 
     * @param u a set of roots of G. 
     * @return true iff a+b is either in u or not a root for all a b in u.
     */
    public boolean definesGroup(int[][] u){
	for( int i = 1; i < u.length; i++)
	    for( int j = 0 ; j< i; j++)
	    {
		int[] c = sums.add(u[i],u[j]);

		if(c != null && findIndex(c) > -1 )
		    return false;
	    }
	return true;

    }

    /**
     * Returns the Cartan Matrix.
     * 
     * @return the Cartan Matrix
     */
    public int[][] getCartan() {
	return cartan;
    }

    /**
     * Test function.
     * 
     * @param s ignored
     * @throws NotARootException thrown if pigs be flyin
     */
    public static void main(String[] s) throws NotARootException{
	ExceptionalGroup g = getGroup(2);
	List<LaurentPolynomial> l = new ArrayList<LaurentPolynomial>();
	l.add(LaurentPolynomial.create("t1"));
	l.add(LaurentPolynomial.create("t2"));
	for (int i = 0; i < 6; i++){
	    System.out.println(g.rootActingOnTorus(g.positiveRoots[i], l));
	    
	}
	for (int i = 0; i < 6; i++){
	    System.out.println(g.h(g.positiveRoots[i], LaurentPolynomial.create(
		    "t")));
	}
	
    }
    
    

}